using System;
using System.Collections.Generic;
using CI.Organism;

namespace CI.Interfaces
{
    /// <summary>
    /// The Organisms DNA
    /// </summary>
    public interface IDNA
    {
        /// <summary>Grow the Organism, run the DNA parser</summary>
        bool Grow();

        /// <summary>Chromosones</summary>
        IChromosomeCollection Chromosomes { get; set; }

        /// <summary>Actioning Genes</summary>
        IGeneCollection ActioningGenes { get; set; }

        /// <summary>
        /// Take this parents DNA and create a new DNA to be put in the new child Organism
        /// Mutate the current DNA and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new dna for child</returns>
        IDNA Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// do a equals comparison of one dna type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="dna">dna to compare against</param>
        /// <returns>true if equal value types</returns>
        bool EqualsValueTypes(IDNA dna);

        /// <summary>
        // updates all the cells in the dna to the cells in the collection as they will have changed after mutations
        /// </summary>
        /// <param name="cells"></param>
        void UpdateMutatedCells(ICellCollection cells);
    }

    /// <summary>
    /// A Chromosone containing Genee
    /// </summary>
    public interface IChromosome
    {
        /// <summary>Chromosone's GUID used to uniquely identify it in the chromosome collection</summary>
        Guid Guid { get; set; }

        /// <summary>Chromosones Gene List</summary>
        IGeneCollection Genes { get; set; }

        /// <summary>
        /// Take this parents Chromosome and create a new Chromosome to be put in the new Organism
        /// Mutate the current Chromosome and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new chromosome for child</returns>
        IChromosome Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// do a equals comparison of one chromosome type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="chromosome">chromosome to compare against</param>
        /// <returns>true if equal value types</returns>
        bool EqualsValueTypes(IChromosome chromosome);
    }

    /// <summary>
    /// Collection class containing a list of  Chromosone's
    /// </summary>
    public interface IChromosomeCollection : IList<IChromosome>
    {
        /// <summary>
        /// Take this parents Chromosomes and create a new Chromosomes collection to be put in the new Organism
        /// Mutate the current Chromosomes and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new chromosomes for child</returns>
        IChromosomeCollection Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// Find the Chromosone with the specifed guid
        /// </summary>
        /// <param name="guid">guid to find</param>
        /// <returns>Chromosone</returns>
        IChromosome Find(Guid guid);
    }

    /// <summary>
    /// Individual Gene, sub unit of a chromosone, this perfoms a operation on a cell
    /// </summary>
    public interface IGene
    {
        /// <summary>Gene's GUID used to uniquely identify it in the chromosome </summary>
        Guid Guid { get; set; }

        /// <summary>the Organism(current) the genes will be acting on</summary>
        IOrganism Organism { get; set; }

        /// <summary>Action Type</summary>
        ActionType ActionType { get; set; }

        /// <summary>If the Gene action type has been actioned then don't process it</summary>
        bool Actioned { get; set; }

        /// <summary>The list of requirements to forefill to action the gene</summary>
        IRequirementCollection Requirements { get; set; }

        /// <summary>Is the gene actionable, eg does it meet the requirements in the list</summary>
        bool Actionable();

        /// <summary>Carry out the action for the gene</summary>
        void Action();

        /// <summary>
        /// Take this parents Gene and create a new Gene to be put in the new child organism
        /// Mutate the current Gene and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new gene for child</returns>
        IGene Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// do a equals comparison of one gene type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="gene">gene to compare against</param>
        /// <returns>true if equal value types</returns>
        bool EqualsValueTypes(IGene gene);

    }

    /// <summary>
    /// Collection class containing a list of Gene's
    /// </summary>
    public interface IGeneCollection : IList<IGene>
    {
        /// <summary>
        /// Take this parents Genes and create a new Gene Collection to be put in the new child organism
        /// Mutate the current Genes and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new gene collection for child</returns>
        IGeneCollection Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// Find the gene with the specifed guid
        /// </summary>
        /// <param name="guid">guid to find</param>
        /// <returns>Gene</returns>
        IGene Find(Guid guid);

    }

    // todo : create IMutatableCollection and etc...


    /// <summary>
    /// Requirement Item that have to be met before the Gene action can be activated
    /// </summary>
    public interface IRequirement
    {
        /// <summary>Gene's GUID used to uniquely identify it in the requirement </summary>
        Guid Guid { get; }

        /// <summary>
        /// Does the requirement type meet the requirements
        /// </summary>
        /// <returns>True if it meets the requirements else false</returns>
        bool State();

        /// <summary>
        /// Take this parent Requirement and create a new requirement to be put in the new child organism
        /// Mutate the current requirement and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new requirement for child</returns>
        IRequirement Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>Comparison Type then checking state, eg equal, less then, greater then</summary>
        ComparisonType ComparisonType { get; }

        /// <summary>
        /// do a equals comparison of one requirement type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="requirement">requirement to compare against</param>
        /// <returns>true if equal value types</returns>
        bool EqualsValueTypes(IRequirement requirement);
    }

    /// <summary>
    /// Collection class containing the list of the requirments
    /// </summary>
    public interface IRequirementCollection : IList<IRequirement>
    {
        /// <summary>
        /// Take this parent Requirements and create a new requirement collection to be put in the new child organism
        /// Mutate the current requirements and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new requirements for child</returns>
        IRequirementCollection Mutate(double mutationRate, IOrganism childOrganism);

        /// <summary>
        /// Find the requirement with the specifed guid
        /// </summary>
        /// <param name="guid">guid to find</param>
        /// <returns>requirement</returns>
        IRequirement Find(Guid guid);
    }

    /// <summary>Action type that Gene can invoke if it meets it requirements</summary>
    public enum ActionType : int
    {
        /// <summary>
        /// Unknown, and if this value turns up it could be the sign of an error
        /// </summary>
        Unknown = 0,
        /// <summary>
        /// Action type of adding a cell, eg. add neuron, happens when growing
        /// </summary>
        AddCell = 1,
        /// <summary>
        /// Action type of deleting a cell, eg. deleting a neuron usually happens to destroy a cell in ageing, but it still exists in environment
        /// </summary>
        DelCell = 2,
        /// <summary>
        /// The cell is dead and has been consumed so remove it from the environment
        /// </summary>
        RemoveCell = 3,
        /// <summary>
        /// Not applicable
        /// </summary>
        NotApplicable = 4,
    };

    /// <summary>Comparison Type then checking state, eg equal, less then, greater then</summary>
    public enum ComparisonType : int
    {
        /// <summary>
        /// Unknown, and if this value turns up it could be the sign of an error
        /// </summary>
        Unknown = 0,
        /// <summary>Equal</summary>
        Equal = 1,
        /// <summary>Greater than comparison</summary>
        GreaterThan = 2,
        /// <summary>Less then comparison</summary>
        LessThan = 3,
    }

}
